#ifndef STRATEGY_H
#define STRATEGY_H

#include <functional>
#include <memory>
#include <stdint.h>
#include <cmath>
#include <exception>

#include "GameState.h"
#include "Common.h"
#include "IOWorker.h"
#include "Algorithm.h"

class Strategy
{
private:



    // end должен создаваться через new !!!!!!! если муравей не найден, то end == nullptr

    /*
     * Требования:
     *
     */

    static void setFoodState(GameState & st)
    {
        // выставляем статус "занят едой"
        int32_t row;
        int32_t column;
        char foodAntMove;
        for (auto it : st.foods)
        {
            // инициализация
            foodAntMove = 'o';
            row = -1;
            column = -1;
            bool antIsFound = false;
            //поиск ближайшего к еде муравья
            try
            {
                antIsFound = Algorithm::findCellWithType(st, it->row(), it->column(), row, column, ANT);
            }
            catch (const exception & ex)
            {
                throw "Algorithm::findCellWithType";               
            }
            
            if (antIsFound)
            {
                ACell * antCell = st.getXY(row, column);
                
                if (antCell->getType() == ANT)
                {
                    Ant * pAnt = reinterpret_cast<Ant*>(antCell);
                    
                    if ((pAnt->isMyAnt()) && (!pAnt->isBusy()))
                    {
                        bool pathIsFound = false;
                        try
                        {
                            pathIsFound = Algorithm::findASPath(st, *pAnt, it->row(), it->column(), foodAntMove);
                        }
                        catch (const exception & ex)
                        {
                            throw "Algorithm::findASPath";
                        }

                        if (pathIsFound)
                        {
                            pAnt->setAntState(GOEZ_FOR_FOOD);
                            st.addMove(pAnt, foodAntMove);
                            /*  
                             * Удаляем муравья. Это происходит если он походил
                             *  или если он УЖЕ не может ходить
                             */
                            shared_ptr<Ant> ptrToErase(new Ant(*pAnt));
                            st.myAnts.erase(ptrToErase);

                        }

                    }
                }
            }
           
                        
                    
        }
    }

    static void makeRandomMove(GameState & st, const GameConf & cnf, shared_ptr<Ant> & pAnt, int32_t recDepth = 0)
    {
        if (recDepth <= 4)
        {
            const char moves[] = {'n', 'e', 's', 'w'};
            if (pAnt->getAntState() == DO_NICHT)
            {
                Ant & ant = *(pAnt.get());

                int32_t randomMoveIndex = IOWorker::getRandomInt(0, 3);
                char move = moves[randomMoveIndex];
                if (st.antCanGo(ant, move))
                {
                    ant.setAntState(MAKE_RANDOM_MOVE);
                    st.addMove(ant, move);
                    st.myAnts.erase(pAnt);
                }
                else
                {
                    makeRandomMove(st, cnf, pAnt, recDepth + 1);
                }

            }
        }
    }
    
    static void setSlackerState(GameState & st, const GameConf & cnf)
    {
        /*
         * Если я вижу вражеский муравейник, то я попробую идти к нему
         */
        for (auto pAnt : st.myAnts)
        {
            if (pAnt->getAntState() == DO_NICHT)
            {
                Strategy::makeRandomMove(st, cnf, pAnt);
            } 
        }
    }
    
    
    static void moveToStr(const Move & move, string & str)
    {
        if (move.getMove() != 'o')
        {
            stringstream ss;
            ss << "o " << move.getAnt().row() << ' ' << move.getAnt().column() << ' ' << move.getMove();
            str =  ss.str();
        }
        else
        {
            str =  "";
        }
    }
public:

    static void setAntsState(GameState & st, const GameConf & cnf)
    {
        /*
         * После каждого шага, муравьи, которым сказали, что им делать,
         * 		пропадают из st.myAnts.
         */
        Strategy::setFoodState(st);
        Strategy::setSlackerState(st, cnf);
    }
    
        
    static void collisionDetect(GameState & st)
    {
        vector<string> correctMoves;
        sort(st.moves.begin(), st.moves.end());
        // теперь величины с одинаковым dest Рядом
        auto moveIt = st.moves.begin();
        while (moveIt != st.moves.end())
        {
            auto it = moveIt;
            // проматываем одинаковые
            while ((it != st.moves.end()) && (*it == *moveIt))
            {
                it ++;
            }
            
            // вот из этих мы должны 1 выбрать. пусть пока будет первый
            for (auto i = moveIt; i != it; i++)
            {
                string s;
                Strategy::moveToStr(*i, s);
                if (!s.empty())
                {
                    st.filteredMovies.push_back(s);
                   
                }
                
                break;
            }
            
            moveIt = it;
        }
        
    }
};


#endif /* STRATEGY_H */
